package image.color;

/**
 * Stores the R, G, B values of a color as ints, 
 * used when accuracy to decimal places is required. 
 * Storage per Color_int is 96-bits (3 times 32-bits)
 * 
 * @author Shimu
 *
 */
public class Color_Int implements Color<Color_Int> {

    private int R, G, B;

    public final static Color_Int WHITE, BLACK, RED, GREEN, BLUE, YELLOW,
            ORANGE, BROWN, TURQUOISE, PINK, PURPLE, GOLD, SILVER;

    static {
        WHITE = new Color_Int(255, 255, 255);
        BLACK = new Color_Int(0, 0, 0);
        RED = new Color_Int(255, 0, 0);
        GREEN = new Color_Int(0, 255, 0);
        BLUE = new Color_Int(0, 0, 255);
        //GREEN = new Color_int(34, 139, 34);
        YELLOW = new Color_Int(255, 255, 0);
        ORANGE = new Color_Int(255, 140, 0);
        BROWN = new Color_Int(165, 42, 42);
        TURQUOISE = new Color_Int(0, 206, 209);
        PINK = new Color_Int(255, 105, 180);
        PURPLE = new Color_Int(160, 32, 240);

        GOLD = new Color_Int(255, 215, 0);
        SILVER = new Color_Int(192, 192, 192);
    }

    // protected boolean edge, connected;
    public int getR() {
        return R;
    }

    public int getG() {
        return G;
    }

    public int getB() {
        return B;
    }

    public Color_Int(int intRep) {
        R = (intRep >> 16) & 255;
        G = (intRep >> 8) & 255;
        B = intRep & 255;
    }

    public Color_Int() {
        this(0, 0, 0);
    }

    public Color_Int(int R, int G, int B) {
        this.R = R;
        this.G = G;
        this.B = B;
    }

    public Color_Int(Color_Int color) {
        this.R = color.R;
        this.G = color.G;
        this.B = color.B;
    }

    @Override
    public void add(Color_Int c) {
        R += c.R;
        G += c.G;
        B += c.B;
    }

    public void add(int R, int G, int B) {
        this.R += R;
        this.G += G;
        this.B += B;
    }

    public static Color_Int add(Color_Int c1, Color_Int c2) {
        return new Color_Int(c1.R + c2.R, c1.G + c2.G, c1.B + c2.B);
    }

    @Override
    public void subtract(Color_Int c) {
        this.R -= c.R;
        this.G -= c.G;
        this.B -= c.B;
    }

    public void subtract(int R, int G, int B) {
        this.R -= R;
        this.G -= G;
        this.B -= B;
    }

    @Override
    public void scale(double scalar) {
        R *= scalar;
        G *= scalar;
        B *= scalar;
    }

    public static Color_Int subtract(Color_Int c1, Color_Int c2) {
        return new Color_Int(c1.R - c2.R, c1.G - c2.G, c1.B - c2.B);
    }

    public static Color_Int scale(Color_Int c, int scalar) {
        return new Color_Int(c.R * scalar, c.G * scalar, c.B * scalar);
    }

    public static Color_Int max(Color_Int c1, Color_Int c2) {
        return new Color_Int(Math.max(c1.R, c2.R), Math.max(c1.G, c2.G),
                Math.max(c1.B, c2.B));
    }

    @Override
    public int intRep() {
        return (65536 * (int) R + 256 * (int) G + (int) B);
    }

    public static int intRep(double R, double G, double B) {
        return (65536 * (int) R + 256 * (int) G + (int) B);
    }

    /*
    public void check() {
    check(0);
    }

    public void check(int threshold) {
    if (R < threshold) {
    R = 0;
    }
    if (G < threshold) {
    G = 0;
    }
    if (B < threshold) {
    B = 0;
    }
    }
     */
    /*
    public boolean above(int threshold) {
    return above(threshold, threshold, threshold);
    }
    
     */
    public boolean above(Color_Int threshold) {
        return (R > threshold.R) && (G > threshold.G) && (B > threshold.B);
    }

    public boolean below(Color_Int threshold) {
        return (R < threshold.R) && (G < threshold.G) && (B < threshold.B);
    }

    /*
    public boolean above(double RThreshold, double GThreshold, double BThreshold) {
    return (R < RThreshold) || (G < GThreshold) || (B < BThreshold)) {
    return false;
    }
    return true;
    }
    //     */
    @Override
    public void invert() {
        R = -R;
        G = -G;
        B = -B;
    }

    public Color_Short toColorInt() {
        return new Color_Short(R, G, B);
    }

    public static Color_Int[] toColorDouble(int[] intArray, int w, int h) {
        Color_Int[] newArray = new Color_Int[w * h];

        int r_index;
        for (int r = 0; r < h; r++) {
            r_index = r * w;
            for (int c = 0; c < w; c++) {
                newArray[r_index] = new Color_Int(intArray[r_index]);
                r_index++;
            }
        }
        return newArray;
    }

    public int toGray() {
        double average = (R + G + B) / 3.0;
        return intRep(average, average, average);
    }

    @Override
    public void clamp() {
    }
    /*
    @Override
    public void clamp() {
    if (R < 0) {
    R = 0;
    } else if (R > 255) {
    R = 255;
    }

    if (G < 0) {
    G = 0;
    } else if (G > 255) {
    G = 255;
    }

    if (B < 0) {
    B = 0;
    } else if (B > 255) {
    B = 255;
    }
    }
     * 
     */

    public Color_Int average(Color_Int c) {
        return new Color_Int((R + c.R) / 2, (G + c.G) / 2, (B + c.B) / 2);
    }

    public boolean equals(Color_Int c) {
        if ((R == c.R) && (G == c.G) && (B == c.B)) {
            return true;
        }
        return false;
    }

    @Override
    public String toString() {
        return "Color: [" + String.format("%.4g", R) + ", "
                + String.format("%.4g", G) + ", " + String.format("%.4g", B)
                + "]";
    }

    public static void main(String args[]) {
        Color_Int test = new Color_Int(134, 100, 100);
        System.out.println(test);
        System.out.println(test.intRep());
        System.out.println((test.intRep() >> 16) & 255);
    }
}
